package com.ruoyi.bluebera.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.bluebera.domain.*;
import com.ruoyi.bluebera.service.*;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.net.Proxy;
import java.net.InetSocketAddress;


import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component("BeraTxFetcher")

public class BeraTxFetcher {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS) // 连接超时
            .readTimeout(15, TimeUnit.SECONDS)    // 读超时
            .writeTimeout(10, TimeUnit.SECONDS)   // 写超时
            //.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 10080))) // 本地 HTTP 代理
            .build();

    @Autowired
    private IBizOrdersService bizOrdersService;
    @Autowired
    private IBizTxScanLogsService bizTxScanLogsService;
    @Autowired
    private IBizTxRecordService bizTxRecordService;
    @Autowired
    private IBizExchangeRatesService bizExchangeRatesService;
    @Autowired
    private IBizUsersService bizUsersService;

    public void checkBERAStatus(){
        BizUsers bizUsers = new BizUsers();
        bizUsers.setValid(0);
        List<BizUsers> list = bizUsersService.selectBizUsersList(bizUsers);
        for (BizUsers each : list) {
            checkBERAStatus(each.getWalletAddress());
        }
    }
    @Transactional
    public void checkBERAStatus(String receiveBeraAddress){

        // scan bera tx
        try {
            List<BizTxRecord> list = fetchTxRecords(TaskConstants.BERA_CHAINId, receiveBeraAddress, TaskConstants.BERA_OFFSET);
            for (BizTxRecord record : list) {
                BizTxRecord tx = new BizTxRecord();
                tx.setHash(record.getHash());
                if(bizTxRecordService.selectBizTxRecordList(tx).size()==0) {
                    bizTxRecordService.insertBizTxRecord(record);
                }
            }
        } catch (IOException e) {
            System.err.println("Failed to fetch transactions: " + e.getMessage());
        }

        // 1. get all preprocessing
        BizOrders bizOrders = new BizOrders();
        bizOrders.setTxStatus(TaskConstants.STATUS_PROCESSING);
        bizOrders.setNetwork(TaskConstants.BERA_CHAINId);
        List<BizOrders> list = bizOrdersService.selectBizOrdersList(bizOrders);
        // 2. process according token
        for (BizOrders order : list) {

            BizTxRecord txRecord = new BizTxRecord();
            txRecord.setHash(order.getTxHash());
            txRecord.setChainId(TaskConstants.BERA_CHAINId);
            // change order status and txstatus
            List<BizTxRecord> txRecordList = bizTxRecordService.selectBizTxRecordList(txRecord);
            for(BizTxRecord item : txRecordList) {
                if (item.getConfirmations()>TaskConstants.CONFIRM_COUNT) {
                    // add content to tx log
                    BizTxScanLogs bizTxScanLogs = new BizTxScanLogs();
                /*
                amount DECIMAL(36, 18) default NULL COMMENT '数量',
                bluebera_amount DECIMAL(36, 18) default NULL COMMENT '兑换的bluebera数量',
                rate_to_bluebera DECIMAL(18, 8) default NULL COMMENT '兑换bluebera汇率',
                 */
                    //  need tx info
                    bizTxScanLogs.setOrderId(order.getId());
                    bizTxScanLogs.setPaymentAddress(item.getFromAddr());  // from block
                    bizTxScanLogs.setTxHash(order.getTxHash());
                    bizTxScanLogs.setTokenSymbol(order.getTokenSymbol());
                    bizTxScanLogs.setNetwork(order.getNetwork());

                    bizTxScanLogs.setAmount(item.getValue()); // from block
                    BizExchangeRates rateToBluebera = bizExchangeRatesService.selectClosestExchangeRate(item.getBlockTime()); // block time
                    bizTxScanLogs.setRateToBluebera(rateToBluebera.getRateToBluebera());
                    bizTxScanLogs.setBlueberaAmount(item.getValue().divide(rateToBluebera.getRateToBluebera())); // from block value/rate
                    bizTxScanLogs.setScannedAt(new Date());
                    bizTxScanLogs.setScanStatus(TaskConstants.STATUS_COMPLETED);
                    bizTxScanLogsService.insertBizTxScanLogs(bizTxScanLogs);

                    // update order
                    order.setTxStatus(TaskConstants.STATUS_COMPLETED);
                    order.setStatus(TaskConstants.STATUS_COMPLETED);
                    bizOrdersService.updateBizOrders(order);
                    logger.warn("bera updated order={}", order);
                }
            }
        }

    }

    public List<BizTxRecord> fetchTxRecords(String chainId, String address, int offset) throws IOException {
        List<BizTxRecord> records = new ArrayList<>();

        HttpUrl url = HttpUrl.parse(TaskConstants.BASE_URL).newBuilder()
                .addQueryParameter("chainid", chainId)
                .addQueryParameter("module", "account")
                .addQueryParameter("action", "txlist")
                .addQueryParameter("address", address)
                .addQueryParameter("startblock", "0")
                .addQueryParameter("endblock", "99999999")
                .addQueryParameter("page", "1")
                .addQueryParameter("offset", String.valueOf(offset))
                .addQueryParameter("sort", "desc")
                .addQueryParameter("apikey", TaskConstants.API_KEY)
                .build();
        logger.info("wdy url={}", url);
        Request request = new Request.Builder().url(url).get().build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected HTTP code: " + response.code());
            }

            String body = response.body().string();
            JSONObject json = JSON.parseObject(body);

            if (!"1".equals(json.getString("status"))) {
                throw new IOException("API error: " + json.getString("message"));
            }

            JSONArray result = json.getJSONArray("result");
            logger.info("wdy result={}", result);
            for (int i = 0; i < result.size(); i++) {
                JSONObject tx = result.getJSONObject(i);
                String receiverAddr = tx.getString("to");
                if(receiverAddr.equalsIgnoreCase(address)){
                    BizTxRecord record = new BizTxRecord();

                    record.setChainId(chainId);
                    record.setBlockNumber(tx.getLong("blockNumber"));
                    record.setBlockTime(timestampToDate(tx.getLong("timeStamp")));
                    record.setHash(tx.getString("hash"));
                    record.setFromAddr(tx.getString("from"));
                    record.setToAddr(tx.getString("to"));
                    record.setValue(weiToEther(tx.getString("value")));
                    record.setConfirmations(tx.getLong("confirmations"));

                    records.add(record);
                }
            }
        }

        return records;
    }

    private static Date timestampToDate(Long timestamp) {
        return new Date(timestamp * 1000); // seconds to milliseconds
    }

    private static BigDecimal weiToEther(String wei) {
        return new BigDecimal(wei).divide(new BigDecimal("1000000000000000000")); // 1 ether = 1e18 wei
    }

    // 测试方法
    public static void main(String[] args) {
        /*
        try {
            List<BizTxRecord> list = fetchTxRecords("80094", "0x6EaC6A279ACCB130eC2A8621E946386Bb474E1c0", 10);
            list.forEach(System.out::println);
        } catch (IOException e) {
            System.err.println("Failed to fetch transactions: " + e.getMessage());
        }
        */
    }
}

